package com.allwees.bs.c.module.payment.service.impl;

import com.allwees.bs.c.module.order.dto.OrderDTO;
import com.allwees.bs.c.module.order.entity.OrderEntity;
import com.allwees.bs.c.module.order.entity.OrderItemEntity;
import com.allwees.bs.c.module.order.repository.OrderItemRepository;
import com.allwees.bs.c.module.order.repository.OrderRepository;
import com.allwees.bs.c.module.order.service.IOrderService;
import com.allwees.bs.c.module.payment.dto.PaymentPaypalDTO;
import com.allwees.bs.c.module.payment.entity.PaymentLogEntity;
import com.allwees.bs.c.module.payment.req.PaymentCaptureReq;
import com.allwees.bs.c.module.payment.req.PaymentPayPalAppCancelReq;
import com.allwees.bs.c.module.payment.req.PaymentPayPalAppCreateReq;
import com.allwees.bs.c.module.payment.req.PaymentPayPalCheckoutReq;
import com.allwees.bs.c.module.payment.service.IPaymentLogService;
import com.allwees.bs.core.model.order.wf.order.EOrderItemAction;
import com.allwees.bs.core.model.order.wf.order.EOrderState;
import com.allwees.bs.core.model.payment.enums.EPaymentType;
import com.allwees.bs.core.modelbase.constant.ResultEnum;
import com.allwees.bs.core.modelbase.exception.BusinessException;
import com.allwees.support.payment.EPayMethod;
import com.allwees.support.payment.model.PaymentInfo;
import com.allwees.support.payment.payby.PaybyAccountStrategy;
import com.allwees.support.payment.payby.configuration.PaybyProperties;
import com.allwees.support.payment.paypal.PaypalAccountStrategy;
import com.paypal.api.payments.Payment;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.Map;

@Slf4j
@Service
public class PaybyServiceImpl {
    @Autowired
    private OrderRepository orderRepository;
    @Autowired
    private OrderItemRepository orderItemRepository;
    @Autowired
    private PaybyProperties paybyProperties;
    @Autowired
    private IPaymentLogService paymentLogService;
    @Autowired
    private IOrderService orderService;

    public PaymentPaypalDTO createPayment(PaymentPayPalCheckoutReq req) {
        OrderEntity order = canPayOrder(req.getOrderUuid());
        if (order.isAmtPayedOfCoupon()) {
            return null;
        }
        PaymentInfo paymentInfo = new PaymentInfo()
                .setPlatform(req.getPlatform())
                .setPaybyProperties(paybyProperties)
                .setOrder(order)
                .setOrderItems(orderItemRepository.findOrderItems(order.getUuid()))
                .setDeviceId(req.getDeviceId());

        Map<String, String> createPayMap = PaybyAccountStrategy.create(paymentInfo);
        String token = createPayMap.get("token");

        PaymentLogEntity paymentLog = paymentLogService.create(createPayMap.get("token"), IPaymentLogService.PAYMENT_STATE_CREATED, EPayMethod.PAYBY, order);

        return PaymentPaypalDTO.builder()
                .approvalURL(token)
                .expiredAt(paymentLog.getPaymentExpiresAt())
                .payToken(paymentLog.getPaymentToken())
                .signedPayToken(createPayMap.get("signedToken"))
                .paymentUuid(paymentLog.getUuid())
                .orderUuid(req.getOrderUuid())
                .build();
    }

    public OrderDTO orderPayed(PaymentCaptureReq req) {
//        String paymentNo = PaypalAccountStrategy.capture(req.getOrderUuid(), req.getToken());
        PaymentLogEntity paymentLog = paymentLogService.payed(req.getOrderUuid(), req.getPayerId(), req.getToken());

        // 支付成功，通知订单修改状态
        return this.orderService.payOrder(paymentLog.getOrderUuid(), paymentLog.getUuid(), EPaymentType.PAYBY);
    }

    public void paybyCaptureWebHooks(String orderUuid, String token) {
        OrderEntity order = null;
        if (StringUtils.isBlank(orderUuid)) {
            PaymentLogEntity paymentLog = paymentLogService.findByOrderUuid(token);
            Assert.notNull(paymentLog, "not found payment log");
            orderUuid = paymentLog.getOrderUuid();
        }

        order = orderRepository.getByUuid(orderUuid);
        Assert.notNull(order, "not found order");

        if (order.getPayed() != null && order.getPayed()) {
            return;
        }
        PaymentCaptureReq captureReq = new PaymentCaptureReq();
        captureReq.setToken(token);
        captureReq.setOrderUuid(orderUuid);
        orderPayed(captureReq);
    }

    public void paybyRefundedWebHooks(String orderItemUUid) {
        OrderItemEntity orderItemEntity = orderItemRepository.getByUuid(orderItemUUid);
        orderItemEntity.signal(EOrderItemAction.CASH_REFUNDED);
        orderItemEntity.setRefundAble(false);
        orderItemRepository.save(orderItemEntity);
    }

    public void createAppPayment(PaymentPayPalAppCreateReq req) {
        OrderEntity order = canPayOrder(req.getOrderUuid());
        paymentLogService.create(req.getToken(), IPaymentLogService.PAYMENT_STATE_APPROVED, EPayMethod.PAYBY, order);
    }

    public void cancelPayment(PaymentPayPalAppCancelReq req) {
        paymentLogService.cancel(req.getOrderUuid());
    }

    public Map<String, String> queryPaymentFromPayby(String merchantOrderNo) {
        log.info("queryPayment merchantOrderNo:{}", merchantOrderNo);
        Map<String, String> queryResult = PaybyAccountStrategy.queryResult(merchantOrderNo);
        log.info("queryPayment merchantOrderNo:{} result:{}", merchantOrderNo, queryResult);

        return queryResult;
    }


    // @Deprecated
    public OrderDTO appCapture(PaymentCaptureReq req) {
        Payment payment = PaypalAccountStrategy.appCapture(req.getToken(), req.getPayerId(), paybyProperties.getAppId());

        PaymentLogEntity paymentLog = paymentLogService.payed(req.getOrderUuid(), req.getPayerId(), payment.getTransactions().get(0).getRelatedResources().get(0).getSale().getId());
        return this.orderService.payOrder(paymentLog.getOrderUuid(), paymentLog.getUuid(), EPaymentType.PAYPAL);
    }

    private OrderEntity canPayOrder(String orderUuid) {
        // 获取订单，并根据订单的情况和信息进行处理
        OrderEntity order = this.orderRepository.getByUuid(orderUuid);
        if (order == null) {
            throw BusinessException.getInstance(ResultEnum.NOT_FOUND);
        }

        // 只有待支付的情况下才能进行支付
        if (!EOrderState.CREATED.equals(order.getState())) {
            throw BusinessException.getInstance(ResultEnum.PAYMENT_ORDER_STATE_IS_NOT_UNPAID);
        }
        return order;
    }

    public OrderEntity queryOrderStatus(String orderUuid) {
        return this.orderRepository.getByUuid(orderUuid);
    }

    public PaymentLogEntity queryPayLog(String orderUuid) {
        return this.paymentLogService.findByOrderUuid(orderUuid);
    }

}

